package com.operation;

import com.operation.address.LogicAddress;
import com.operation.job.Job;
import com.operation.page.PageList;
import com.operation.page.PageReplacement;

import java.util.Scanner;

/**
 * 程序主运行类，整合其他方法及相关资源，完成请求分页调度逻辑
 */
public class Main {


    public static void main(String[] args) {


        /*
            定义全局参数，为了方便修改，封装成类GlobalArgument,例如
            GlobalArgument.JobStartAddress
            模拟程序执行过程，随机生成一些页的页面号引用串
            初始时内存块中没有任何页面，根据第一个逻辑地址将相关页导入内存块中，修改页表和快表
                第一个数据结构：页表设计
            后续需要导入页面时，先查快表再查页表，如果找到直接记入其物理地址；否则按照上面过程
            当内存块已满，需要页面换出的时候，请求分页，采用置换算法
            FIFO：可以直接借助队列
            LRU：借助栈，还是手动实现一个栈，因为在这个过程中需要使用到一些链表的操作，因此还是使用list
         */
        //添加模式控制
        int model = 0;
        Scanner scanner = new Scanner(System.in);
        System.out.println("使用自定义数据? 1-是；0-否");
        model = scanner.nextInt();
        if (model == 1) {
            GlobalArgument.input();
        }
        //新建作业，在外存中地址0~319
        Job job = new Job("job1", GlobalArgument.JobStartAddress, GlobalArgument.JobEndAddress);
        /*
            提供程序的三种执行方式
                顺序执行
                跳跃执行（每条指令都跳跃）
                正常模拟
         */
        //选择程序执行方式
        scanner=new Scanner(System.in);
        LogicAddress[] logicAddresses = null;
        System.out.println("选择程序执行方式：0-顺序执行；1-跳跃执行；2-自定义执行；3-真实执行");
        model=scanner.nextInt();
        switch (model) {
            case 0 : logicAddresses = job.sequentialExecute();break;
            case 1 : logicAddresses = job.skipExecution();break;
            case 2 : logicAddresses = job.customExecution();break;
            case 3 : logicAddresses = job.actualExecution(20);break;
            default : System.out.println("从新输入");break;
        }
        model=0;
        System.out.println("选择页面置换算法? 1-fcfs；0-lru");
        model = scanner.nextInt();

        //新建快表和慢表
        PageList fastTable = new PageList("快表", GlobalArgument.memorySize);
        PageList pageTable = new PageList("页表", GlobalArgument.memorySize);

        //置换类
        PageReplacement fastReplacement = new PageReplacement("快表置换类", GlobalArgument.memorySize);
        PageReplacement pageReplacement = new PageReplacement("页表置换类", GlobalArgument.memorySize);

        //cpu开始调度
        for (int i = 0; logicAddresses!=null&&i < logicAddresses.length; i++) {
            //展示页表信息
            System.out.println();
            pageTable.display();

            //当前访问的逻辑地址
            LogicAddress logicAddress = logicAddresses[i];
            System.out.println("当前访问的页号为：" + logicAddress.getPageNumber());

            //在快表中查找
            int memoryNumber = fastTable.isHit(logicAddress.getPageNumber());//命中返回内存块号
            if (memoryNumber >= 0) {
                //命中返回物理地址
                System.out.println("------------------------------------" +
                        "在快表中命中--------------------------------------");
            } else {
                //在慢表中查找
                memoryNumber = pageTable.isHit(logicAddress.getPageNumber());
                if (memoryNumber >= 0) {//在慢表中命中
                    System.out.println("++++++++++++++++++++++++++++++++++++" +
                            "在页表中命中++++++++++++++++++++++++++++++++++++++");
                } else {
                    //缺页中断
                    System.out.println("++++++++++++++++++++++++++++++++++++" +
                            "缺页中断，请求相关页++++++++++++++++++++++++++++++++++++++");
                    int replacePage;
                    if (model == 1) replacePage = pageReplacement.fcfs(logicAddress.getPageNumber());
                    else {
                        replacePage = pageReplacement.lru(logicAddress.getPageNumber());
                    }
                    //置换，replacePage为-1时，直接在页表末尾加入表项
                    pageTable.replacePage(replacePage, logicAddress.getPageNumber());
                    pageTable.display();
                }
                //同时更新快表,更新快表时可能需要置换
                int replacePage;
                if(model==1) replacePage = fastReplacement.fcfs(logicAddress.getPageNumber());
                else{
                    replacePage = fastReplacement.lru(logicAddress.getPageNumber());
                }
                //置换，replacePage为-1时，直接在快表末尾加入表项
                fastTable.replacePage(replacePage, logicAddress.getPageNumber());
                memoryNumber = pageTable.isHit(logicAddress.getPageNumber());//确定内存物理块号
            }
            LogicAddress.display(logicAddress, memoryNumber, GlobalArgument.pageSize);
        }
        System.out.println("缺页的总次数为：" + pageReplacement.getPageFault());

    }
}
